package com.kun.video.domain;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.text.StrPool;
import com.kun.video.exception.Assert;
import com.kun.video.exception.BizException;

import java.io.File;
import java.util.List;

/**
 * 文件包装处理工具类
 * <p>封装文件基础信息，提供文件名重构、输出路径生成等操作</p>
 *
 * @author gzc
 * @since 2025/3/3
 **/
public class KunFileWrapper {
    /**
     * 原始文件对象
     */
    private final File inputFile;
    /**
     * 文件名（不包含扩展名）
     */
    private final String inputFileName;
    /**
     * 文件扩展名（不包含点）
     */
    private final String inputFileFormat;
    /**
     * 完整文件名（包含扩展名）
     */
    private final String inputFileNameAndFormat;
    /**
     * 父目录文件对象
     */
    private final File inputParentFile;
    /**
     * 分割符
     */
    private String separator = StrPool.DASHED;

    /**
     * 构造方法，校验并初始化文件基础信息
     *
     * @param inputFile 需要包装的文件对象，必须为存在的文件（非目录）
     * @param separator 分割符
     * @throws BizException 当文件为空、非文件类型或基础信息获取失败时抛出
     */
    public KunFileWrapper(File inputFile, String separator) {
        this(inputFile);
        setSeparator(separator);
    }

    /**
     * 构造方法，校验并初始化文件基础信息
     *
     * @param inputFile 需要包装的文件对象，必须为存在的文件（非目录）
     * @throws BizException 当文件为空、非文件类型或基础信息获取失败时抛出
     */
    public KunFileWrapper(File inputFile) {
        // 基础校验
        if (inputFile == null) {
            throw new BizException("File对象为空");
        }
        if (!inputFile.isFile()) {
            throw new BizException("File对象不是文件类型");
        }

        // 初始化文件基础属性
        this.inputFile = inputFile;
        this.inputFileName = FileNameUtil.getPrefix(inputFile);
        this.inputFileFormat = FileNameUtil.getSuffix(inputFile);
        this.inputFileNameAndFormat = this.inputFileName + StrPool.DOT + this.inputFileFormat;
        this.inputParentFile = inputFile.getParentFile();

        // 关键信息二次校验
        Assert.notBlank(this.inputFileName, "获取输入文件名称为空");
        Assert.notBlank(this.inputFileFormat, "获取输入文件格式为空");
        Assert.notNull(this.inputParentFile, "获取父目录对象为空");
    }

    /**
     * 生成带标记的转换文件名（保持原格式）
     *
     * @param flagText 文件名中插入的标记文本（如时间戳或操作类型）
     * @return 格式示例：originalName-flagText.format
     */
    public String getConvertFileNameAndFormat(String flagText) {
        return getConvertFileNameAndFormat(flagText, this.inputFileFormat);
    }

    /**
     * 生成带标记且指定格式的转换文件名
     *
     * @param flagText   文件名中插入的标记文本
     * @param fileFormat 目标文件格式（扩展名）
     * @return 格式示例：originalName-flagText.newFormat
     */
    public String getConvertFileNameAndFormat(String flagText, String fileFormat) {
        return getConvertFileNameAndFormat(List.of(flagText), fileFormat);
    }

    /**
     * 生成带标记且指定格式的转换文件名
     *
     * @param flagTextList 文件名中插入的标记文本列表
     * @param fileFormat   目标文件格式（扩展名）
     * @return 格式示例：originalName-flagText.newFormat
     */
    public String getConvertFileNameAndFormat(List<String> flagTextList, String fileFormat) {
        Assert.notEmpty(flagTextList, "标记文本列表为空");
        Assert.notBlank(fileFormat, "输出文件格式为空");
        // 防止标记文本含非法字符
        flagTextList.forEach(this::checkFileName);
        return this.inputFileName + separator
                + String.join(separator, flagTextList)
                + StrPool.DOT + fileFormat;
    }

    /**
     * 获取默认输出路径下的文件对象（保持原格式）
     */
    public File getOutputFile(String flagText) {
        return getOutputFile(flagText, this.inputFileFormat);
    }

    /**
     * 获取默认输出路径下的文件对象（指定格式）
     */
    public File getOutputFile(String flagText, String fileFormat) {
        return getOutputFile(this.inputParentFile.getAbsolutePath(), flagText, fileFormat);
    }

    /**
     * 在指定父目录下生成输出文件对象
     *
     * @param parentFilePath 输出目录绝对路径
     * @param flagText       标记文本
     * @param fileFormat     文件格式
     * @return 拼接后的完整文件对象，自动处理路径格式问题
     */
    public File getOutputFile(String parentFilePath, String flagText, String fileFormat) {
        Assert.isTrue(checkFilePath(parentFilePath), "文件路径【{}】格式错误！", parentFilePath);

        // 路径容错处理：当传入的是文件路径时，自动切换为同级目录
        File parentFile = new File(parentFilePath);
        if (parentFile.isFile()) {
            parentFile = inputFile.getParentFile();
        }

        // 拼接完整输出路径
        String outputFilePath = parentFile.getAbsolutePath()
                + File.separator
                + getConvertFileNameAndFormat(flagText, fileFormat);
        return new File(outputFilePath);
    }

    /**
     * 通过完整文件名生成输出文件（默认父目录）
     */
    public File getOutputFileByName(String outputFileNameAndFormat) {
        return getOutputFileByName(this.inputParentFile.getAbsolutePath(), outputFileNameAndFormat);
    }

    /**
     * 通过分离文件名和格式生成输出文件
     */
    public File getOutputFileByName(String parentFilePath, String outputFileName, String fileFormat) {
        return getOutputFileByName(parentFilePath, outputFileName + StrPool.DOT + fileFormat);
    }

    /**
     * 在指定目录下通过完整文件名生成输出文件
     *
     * @param parentFilePath          父目录路径
     * @param outputFileNameAndFormat 完整文件名（需包含扩展名）
     * @throws BizException 当文件名不合法或缺少扩展名时抛出
     */
    public File getOutputFileByName(String parentFilePath, String outputFileNameAndFormat) {
        Assert.notBlank(outputFileNameAndFormat, "输出文件名称为空");
        Assert.isTrue(outputFileNameAndFormat.contains(StrPool.DOT), "输出文件名称缺少格式类型");
        // 校验文件名合法性
        checkFileName(outputFileNameAndFormat);

        return new File(parentFilePath + File.separator + outputFileNameAndFormat);
    }

    /**
     * 校验文件名是否包含非法字符（Windows系统规范）
     *
     * @throws BizException 当存在非法字符时抛出
     */
    private void checkFileName(String outputFileNameAndFormat) {
        if (FileNameUtil.containsInvalid(outputFileNameAndFormat)) {
            Assert.throwBizException("标记文本【{}】存在非法字符！不符合windows系统文件名称格式！", outputFileNameAndFormat);
        }
    }

    /**
     * 校验文件路径是否为绝对路径
     */
    private boolean checkFilePath(String filePath) {
        return FileUtil.isAbsolutePath(filePath);
    }

    public void setSeparator(String separator) {
        this.separator = separator;
    }

    public String getAbsolutePath() {
        return this.inputFile.getAbsolutePath();
    }

    public File getInputFile() {
        return inputFile;
    }

    public String getInputFileName() {
        return inputFileName;
    }

    public String getInputFileFormat() {
        return inputFileFormat;
    }

    public String getInputFileNameAndFormat() {
        return inputFileNameAndFormat;
    }

    public File getInputParentFile() {
        return inputParentFile;
    }

    public String getSeparator() {
        return separator;
    }


}